// SPDX-License-Identifier: GPL-2.0+
/*
 * wdt_operate.c - CSP API of LomboTech Watchdog Driver
 *
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#include "wdt_operate.h"

/* reg access key field */
#define LOMBO_WDOG_RL_KEY_FIELD_VALUE	(0xEE18)

void csp_wdt_unlock_reg(void *base)
{
	reg_wdog_wdog_rl_t reg;

	reg.val = readl(base + LOMBO_WDOG_RL);
	reg.bits.keyfield = LOMBO_WDOG_RL_KEY_FIELD_VALUE;
	writel(reg.val, base + LOMBO_WDOG_RL);
}

void csp_wdt_lock_reg(void *base)
{
	reg_wdog_wdog_rl_t reg;

	reg.val = readl(base + LOMBO_WDOG_RL);
	reg.bits.keyfield = 0;
	writel(reg.val, base + LOMBO_WDOG_RL);
}

void csp_wdt_clr_int_pend(void *base)
{
	reg_wdog_wdog_clr_int_pending_t reg;

	reg.val = readl(base + LOMBO_WDOG_CLR_INT_PENDING);
	reg.bits.clr = 1;
	writel(reg.val, base + LOMBO_WDOG_CLR_INT_PENDING);
}

u32 csp_wdt_get_int_pend(void *base)
{
	reg_wdog_wdog_int_pending_t reg;

	reg.val = readl(base + LOMBO_WDOG_INT_PENDING);
	return reg.bits.pending;
}

void csp_wdt_int_enable(void *base, u32 value)
{
	reg_wdog_wdog_int_en_t reg;

	reg.val = readl(base + LOMBO_WDOG_INT_EN);
	reg.bits.enable = value;
	writel(reg.val, base + LOMBO_WDOG_INT_EN);
}

void csp_wdt_set_store(void *base, u32 value)
{
	reg_wdog_wdog_store_t reg_wdog_wdog_store;
	u32 store = MSEC_TO_STORE(value);

	if (store > 0xffffff)
		store = 0xffffff;
	reg_wdog_wdog_store.val = readl(base + LOMBO_WDOG_STORE);
	reg_wdog_wdog_store.bits.store = store;
	writel(reg_wdog_wdog_store.val, base + LOMBO_WDOG_STORE);
}

void csp_wdt_restart_store(void *base, u32 value)
{
	reg_wdog_wdog_restart_t reg;

	if (value > 0xffffff)
		value = 0xffffff;
	reg.val = readl(base + LOMBO_WDOG_RESTART);
	reg.bits.restart_store = value;
	writel(reg.val, base + LOMBO_WDOG_RESTART);
}

void csp_wdt_set_response_mod(void *base, u32 value)
{
	reg_wdog_wdog_ctrl_t temp;

	temp.val = readl(base + LOMBO_WDOG_CTRL);
	temp.bits.rmod = value;
	writel(temp.val, base + LOMBO_WDOG_CTRL);
}

void csp_wdt_clk(void *base, u32 value)
{
	reg_wdog_wdog_ctrl_t reg;

	reg.val = readl(base + LOMBO_WDOG_CTRL);
	reg.bits.sel = value;
	writel(reg.val, base + LOMBO_WDOG_CTRL);
}

u32 csp_wdt_get_status(void *base)
{
	reg_wdog_wdog_ctrl_t temp;

	temp.val = readl(base + LOMBO_WDOG_CTRL);
	return temp.bits.en;
}

int csp_wdt_enable(void *base)
{
	reg_wdog_wdog_ctrl_t temp;

	temp.val = readl(base + LOMBO_WDOG_CTRL);
	temp.bits.en = 1;
	writel(temp.val, base + LOMBO_WDOG_CTRL);

	return 0;
}

int csp_wdt_disable(void *base)
{
	reg_wdog_wdog_ctrl_t temp;

	temp.val = readl(base + LOMBO_WDOG_CTRL);
	temp.bits.en = 0;
	writel(temp.val, base + LOMBO_WDOG_CTRL);

	return 0;
}

void csp_wdt_restart(void *base)
{
	reg_wdog_wdog_restart_t reg;

	reg.val = readl(base + LOMBO_WDOG_RESTART);
	reg.bits.restart = 1;
	writel(reg.val, base + LOMBO_WDOG_RESTART);
}

void csp_wdt_set_timeout(void *base, u32 value)
{
	csp_wdt_set_store(base, value);
}

void csp_wdt_get_timeleft(void *base, u32 *value)
{
	reg_wdog_wdog_cur_val_t reg;
	u32 store;

	reg.val = readl(base + LOMBO_WDOG_CUR_VAL);
	store = reg.bits.cur_val;
	*value = STORE_TO_MSEC(store);
}

u32 csp_wdt_get_current(void *base)
{
	reg_wdog_wdog_cur_val_t reg;

	reg.val = readl(base + LOMBO_WDOG_CUR_VAL);
	return reg.bits.cur_val;
}

void csp_wdt_set_reboot_time(void *base)
{
	csp_wdt_set_store(base, 1);
	csp_wdt_restart_store(base, 0);
}

void csp_wdt_init_register(void *base)
{
	writel(0x00000000, base + LOMBO_WDOG_INT_EN);
	writel(0x00000000, base + LOMBO_WDOG_STORE);
	writel(0x00000000, base + LOMBO_WDOG_RESTART);
	writel(0x00000030, base + LOMBO_WDOG_CTRL);
}
